home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
alpha.arc
/
DIRUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-02-16
|
13KB
|
499 lines
/* dirutil.c - MS-DOS directory reading routines
*
* Bdale Garbee, N3EUA, Dave Trulli, NN2Z, and Phil Karn, KA9Q
* Directory sorting by Mike Chepponis, K3MC
*/
#include <stdio.h>
#include <stat.h>
#include "global.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE !(FALSE)
#endif
#define REGFILE (ST_HIDDEN|ST_SYSTEM|ST_DIRECT)
#define SET_DTA 0x1a
#define FIND_FIRST 0x4e
#define FIND_NEXT 0x4f
struct dirent {
char rsvd[21];
char attr;
short ftime;
short fdate;
long fsize;
char fname[13];
};
#define NULLENT (struct dirent *)0
struct dirsort {
struct dirsort *prev;
struct dirsort *next;
struct dirent *direntry;
};
#define NULLSORT (struct dirsort *)0
/* Create a directory listing in a temp file and return the resulting file
* descriptor. If full == 1, give a full listing; else return just a list
* of names.
*/
FILE *
dir(path,full)
char *path;
int full;
{
FILE *fp,*tmpfile();
fp = tmpfile();
getdir(path,full,fp);
/* This should be rewind(), but Aztec doesn't have it */
fseek(fp,0L,0);
return fp;
}
/* wildcard filename lookup */
filedir(name,times,ret_str)
char *name;
int times;
char *ret_str;
{
register char *cp,*cp1;
static struct dirent sbuf;
bdos(SET_DTA,&sbuf); /* Set disk transfer address */
/* Find matching file */
if(dos(times == 0 ? FIND_FIRST:FIND_NEXT,0,REGFILE,name,0,0) == -1)
sbuf.fname[0] = '\0';
/* Copy result to output, forcing to lower case */
for(cp = ret_str,cp1 = sbuf.fname; cp1 < &sbuf.fname[13] && *cp1 != '\0';)
*cp++ = tolower(*cp1++);
*cp = '\0';
}
/* do a directory list to the stream
* full = 0 -> short form, 1 is long
*/
getdir(path,full,file)
char *path;
int full;
FILE *file;
{
struct dirent sbuf;
struct stat statbuf;
register char *cp,*cp1;
char dirtmp[20];
int command = FIND_FIRST;
int i = 0;
int cflag = 0;
char temp_name[13]; /* Holds a filename temporarily */
int loop_counter;
int n = 0;
char line_buf[50]; /* for long dirlist */
char cbuf[20],cbuf1[20]; /* for making line_buf */
struct dirsort *prev, *head, *here, *new;
struct dirent *de;
void dir_sort(), format_fname(), commas(), isfree(), free_clist();
unsigned short ax,bx,cx,dx;
unsigned long free_bytes, total_bytes;
char s_free[11], s_total[11];
int malloc_lost = FALSE;
/* Root directory is a special case */
if(path == NULLCHAR || *path == '\0' || strcmp(path,"\\") == 0)
path = "\\*.*";
/* If arg is a directory, append "\*.*" to it.
* This is tricky, since the "stat" system call actually
* calls the DOS "find matching file" function. The stat
* call therefore returns the attributes for the first matching
* entry in the directory. If the arg already ends in *.*,
* stat will match the . entry in the directory and indicate
* that the argument is a valid directory name. Hence the
* heuristic check for '*' in the file name. Kludge...
*/
else if(index(path,'*') == NULLCHAR
&& stat(path,&statbuf) != -1
&& (statbuf.st_attr & ST_DIRECT)) {
if((cp = malloc(strlen(path) + 10)) == NULLCHAR)
return -1;
sprintf(cp,"%s%c%s",path,'\\',"*.*");
path = cp;
cflag = 1;
}
head = NULLSORT; /* No head of chain yet... */
for(;;){
bdos(SET_DTA,&sbuf); /* Set disk transfer address */
if(dos(command, 0, REGFILE, path, 0, 0) == -1)
break;
command = FIND_NEXT; /* Got first one already... */
if(sbuf.fname[0] != '.'){
/* nuke "." and ".." */
n++; /* One more entry */
new = (struct dirsort *) malloc(sizeof(struct dirsort));
if(new == NULLSORT)
malloc_lost = TRUE;
de = (struct dirent *)malloc(sizeof(struct dirent));
if(de == NULLENT)
malloc_lost = TRUE;
if(malloc_lost){
/* Clean up and call other routine */
if(new)free(new);
free_clist(head);
return getdir_nosort(path,full,file);
}
*de = sbuf; /* Copy contents of directory entry struct */
/* Fix up names for easier sorting... pain! */
strcpy(de->fname," "); /* 11 blanks */
cp = sbuf.fname;
cp1 = de->fname;
do *cp1++ = *cp++; while (*cp && *cp != '.');
if(*cp++){
/* If there is an extension */
cp1 = &(de->fname[8]);
do *cp1++ = *cp++; while (*cp);
}
if(!(int)head){
/* Make the first one */
here = head = new;
head->prev = head->next = NULLSORT;
} else {
/* Link on next one */
new->next = NULLSORT;
new->prev = here;
here->next = new;
here = new;
}
new->direntry = de;
} /* IF on "." */
} /* infinite FOR loop */
if(head)
dir_sort(head); /* Make a nice, sorted list */
here = head;
if(here && full){
do {
sbuf = *(here->direntry); /* Copy data for printing */
format_fname(dirtmp,sbuf.fname,sbuf.attr);
/* Long form, give other info too */
sprintf(line_buf,"%-13s",dirtmp);
if(sbuf.attr & ST_DIRECT)
strcat(line_buf," ");/* 11 spaces */
else {
sprintf(cbuf,"%ld",sbuf.fsize);
commas(cbuf);
sprintf(cbuf1,"%10s ",cbuf);
strcat(line_buf,cbuf1); /* Do filesize */
}
sprintf(cbuf,"%2d:%02d %2d/%02d/%02d%s",
(sbuf.ftime >> 11) & 0x1f, /* hour */
(sbuf.ftime >> 5) & 0x3f, /* minute */
(sbuf.fdate >> 5) & 0xf, /* month */
(sbuf.fdate ) & 0x1f, /* day */
(sbuf.fdate >> 9) + 80, /* year */
(i^=1) ? " " : "\n");
strcat(line_buf,cbuf);
fprintf(file,"%s",line_buf);
} while (here = here->next);
if(i & 1)
fprintf(file,"\n");
}
else if(here){
/* This is the short form; make sure >=1 entry */
do {
sbuf = *(here->direntry); /* Copy data for printing */
format_fname(dirtmp,sbuf.fname,sbuf.attr);
fprintf(file,"%s\n",dirtmp);
} while (here = here->next);
}
/* Give back all the memory we temporarily needed... */
free_clist(head);
if(full){
/* Provide additional information only on DIR */
ax = 0x3600; /* AH = 36h, AL = 0 (AL not used) */
dx = 0; /* Default drive */
isfree(&ax,&bx,&cx,&dx);
free_bytes = (unsigned long)ax * (unsigned long)cx;
total_bytes = free_bytes * (unsigned long)dx;
free_bytes *= (unsigned long)bx;
sprintf(s_free,"%ld",free_bytes); commas(s_free);
sprintf(s_total,"%ld",total_bytes); commas(s_total);
if(n)
sprintf(cbuf,"%d",n);
else
strcpy(cbuf,"No");
fprintf(file,"%s file%s. %s bytes free. Disk size %s bytes.\n",
cbuf,(n==1? "":"s"),s_free,s_total);
}
if(cflag)
free(path);
return 0;
}
/* Change working directory */
docd(argc,argv)
int argc;
char *argv[];
{
char dirname[128],*getcwd();
if(argc > 1){
if(chdir(argv[1]) == -1){
printf("Can't change directory\n");
return 1;
}
}
if(getcwd(dirname,0) != NULLCHAR){
printf("\\%s\n",dirname);
}
return 0;
}
/* List directory to console */
dodir(argc,argv)
int argc;
char *argv[];
{
char *path;
if(argc >= 2){
path = argv[1];
} else {
path = "*.*";
}
getdir(path,1,stdout);
return 0;
}
/*
* Return a string with commas every 3 positions.
* If malloc() fails, return original string unmodified.
* else the original string is replace with the string with commas.
*
* The caller must be sure that there is enough room for the resultant
* string.
*
*
* k3mc 4 Dec 87
*/
void
commas(dest)
char *dest;
{
char *src, *core; /* Place holder for malloc */
unsigned cc; /* The comma counter */
unsigned len;
len = strlen(dest);
if( (core = src = (char *)malloc(len+1)) == NULLCHAR)
return;
strcpy(src,dest); /* Make a copy, so we can muck around */
cc = (len-1)%3 + 1; /* Tells us when to insert a comma */
while(*src != '\0'){
*dest++ = *src++;
if( ((--cc) == 0) && *src ){
*dest++ = ','; cc = 3;
}
}
free(core);
*dest = '\0';
}
/*
* This insertion sort adapted from "Writing Efficient Programs" by Jon Louis
* Bentley, Prentice-Hall 1982, ISBN 0-13-070244-X (paperback) p. 65
*
* Run Time (sec) = K * N^2, where K = 21e-6 on my turbo XT clone (SI=2.6).
* This could be improved to perhaps K * N * log2(N) using Quicksort, but,
* as Bentley points out, this insertion sort is actually faster for small
* values of N. His "best" sorting algorithm uses an insertion sort/Quicksort
* hybrid, with the "cutoff" value being about 30 elements.
*
* I have opted for the straight insertion sort because it is quite simple,
* provably correct, and not a terrible performer when N < 1000, which is the
* case for most directories.
*/
void
dir_sort(head)
struct dirsort *head;
{
struct dirsort *here, *backtrack;
struct dirent *de_temp;
for(here = head->next; here != NULLSORT; here = here->next){
backtrack = here;
de_temp = here->direntry;
while(backtrack->prev
&& strcmp(de_temp->fname,backtrack->prev->direntry->fname)<0){
backtrack->direntry = backtrack->prev->direntry;
backtrack = backtrack->prev;
}
backtrack->direntry = de_temp;
}
}
void
format_fname(dest,src,attr)
char *dest, *src;
char attr;
{
char *cp = src+8;
int loop_counter;
for(loop_counter=0; loop_counter<8; loop_counter++){
*dest++ = tolower(*src++);
if(*src == ' ')break;
}
if(strcmp(cp," ") != 0){ /* There is an extension */
*dest++ = '.';
for(loop_counter=0; loop_counter<3; loop_counter++){
*dest++ = tolower(*cp++);
if(*cp == ' ')break;
}
}
if(attr & ST_DIRECT)*dest++ = '\\';
*dest = '\0';
}
void
free_clist(head)
struct dirsort *head;
{
struct dirsort *here;
here = head;
if(here)do{
free(here->direntry);
if(head != here){
free(head);
head = here;
}
} while (here = here->next);
if(head != here){
free(head);
head = here;
}
}
getdir_nosort(path,full,file)
char *path;
int full;
FILE *file;
{
struct dirent sbuf;
struct stat statbuf;
register char *cp,*cp1;
char dirtmp[20];
int command = FIND_FIRST;
int i = 0;
int cflag = 0;
char line_buf[50]; /* for long dirlist */
char cbuf[20],cbuf1[20]; /* for making line_buf */
void format_fname(),commas(),isfree();
unsigned short ax,bx,cx,dx;
unsigned long free_bytes, total_bytes;
char s_free[11], s_total[11];
int n = 0; /* Number of directory entries */
/* Root directory is a special case */
if(path == NULLCHAR || *path == '\0' || strcmp(path,"\\") == 0)
path = "\\*.*";
/* If arg is a directory, append "\*.*" to it.
* This is tricky, since the "stat" system call actually
* calls the DOS "find matching file" function. The stat
* call therefore returns the attributes for the first matching
* entry in the directory. If the arg already ends in *.*,
* stat will match the . entry in the directory and indicate
* that the argument is a valid directory name. Hence the
* heuristic check for '*' in the file name. Kludge...
*/
else if(index(path,'*') == NULLCHAR
&& stat(path,&statbuf) != -1
&& (statbuf.st_attr & ST_DIRECT)) {
if((cp = malloc(strlen(path) + 10)) == NULLCHAR)
return -1;
sprintf(cp,"%s%c%s",path,'\\',"*.*");
path = cp;
cflag = 1;
}
for(;;){
bdos(SET_DTA,&sbuf); /* Set disk transfer address */
if(dos(command,0,REGFILE,path,0,0) == -1)
break;
command = FIND_NEXT; /* Got first one already... */
if(sbuf.fname[0] != '.'){ /* nuke "." and ".." */
if(full){
n++; /* Count 'em */
format_fname(dirtmp,sbuf.fname,sbuf.attr);
sprintf(line_buf,"%-13s",dirtmp);
if(sbuf.attr & ST_DIRECT){
strcat(line_buf," ");/* 11 spaces */
} else {
sprintf(cbuf,"%ld",sbuf.fsize);
commas(cbuf);
sprintf(cbuf1,"%10s ",cbuf);
strcat(line_buf,cbuf1); /* Do filesize */
}
sprintf(cbuf,"%2d:%02d %2d/%02d/%02d%s",
(sbuf.ftime >> 11) & 0x1f, /* hour */
(sbuf.ftime >> 5) & 0x3f, /* minute */
(sbuf.fdate >> 5) & 0xf, /* month */
(sbuf.fdate ) & 0x1f, /* day */
(sbuf.fdate >> 9) + 80, /* year */
(i^=1) ? " " : "\n");
strcat(line_buf,cbuf);
fprintf(file,"%s",line_buf);
} else { /* is short form */
format_fname(dirtmp,sbuf.fname,sbuf.attr);
fprintf(file,"%-13s\n",dirtmp);
}
}
}
if(full){
if(i)
fprintf(file,"\n");
ax = 0x3600; /* AH = 36h, AL = 0 (AL not used) */
dx = 0; /* Default drive */
isfree(&ax,&bx,&cx,&dx);
free_bytes = (unsigned long)ax * (unsigned long)cx;
total_bytes = free_bytes * (unsigned long)dx;
free_bytes *= (unsigned long)bx;
sprintf(s_free,"%ld",free_bytes);
commas(s_free);
sprintf(s_total,"%ld",total_bytes);
commas(s_total);
if(n)
sprintf(cbuf,"%d",n);
else
strcpy(cbuf,"No");
fprintf(file,"%s file%s. %s bytes free. Disk size %s bytes.\n",
cbuf,(n==1? "":"s"),s_free,s_total);
}
if(cflag)
free(path);
return 0;
}